﻿using System;

namespace MLSharp
{
	/// <summary>
	/// A <see cref="Rule"/> is composed of one or more RuleConditions.
	/// </summary>
	public class RuleCondition
	{
		#region Private Methods

		/// <summary>
		/// Gets a string representation of the specified operator.
		/// </summary>
		/// <param name="operatorType">The operation.</param>
		/// <returns></returns>
		private static string GetOperationString(ConditionOperatorType operatorType)
		{
			switch (operatorType)
			{
				case ConditionOperatorType.Equals:
					return "==";
				case ConditionOperatorType.GreaterThan:
					return ">";
				case ConditionOperatorType.LessThanOrEqual:
					return "<=";
				case ConditionOperatorType.NotEqual:
					return "<>";
				default:
					throw new NotImplementedException("The specified operator type is not supported.");
			}
		}

		#endregion

		#region Public Properties

		/// <summary>
		/// The type of the rule condition.
		/// </summary>
		public ConditionOperatorType OperatorType { get; set; }

		/// <summary>
		/// The attribute the condition evaluates.
		/// </summary>
		public string Attribute { get; set; }

		/// <summary>
		/// The value the attribute is compared against.
		/// </summary>
		public object Value { get; set; }

		#endregion

		#region Public Methods

		/// <summary>
		/// Two RuleConditions are equal if they have the 
		/// same property values.
		/// </summary>
		/// <param name="obj"></param>
		/// <returns></returns>
		public override bool Equals(object obj)
		{
			RuleCondition condition = obj as RuleCondition;

			if (condition == null)
			{
				return false;
			}

			//If both values are not null, they better be equal.
			if (Value != null && condition.Value != null)
			{
				return OperatorType == condition.OperatorType
				       && Attribute == condition.Attribute
				       && Value.Equals(condition.Value);
			}
			//If both values are null, just check the remaining attributes.
			else if (Value == null && condition.Value == null)
			{
				return OperatorType == condition.OperatorType
				       && Attribute == condition.Attribute;
			}
			//Otherwise, one is null, one isn't, so they can't be equal.
			else
			{
				return false;
			}
		}

		/// <summary>
		/// Gets a hash code.
		/// </summary>
		/// <returns></returns>
		public override int GetHashCode()
		{
			int hashCode = OperatorType.GetHashCode();

			if (Attribute != null)
				hashCode ^= Attribute.GetHashCode();

			if (Value != null)
			{
				hashCode ^= Value.GetHashCode();
			}

			return hashCode;
		}

		/// <summary>
		/// Gets a print-friendly representation of the condition.
		/// </summary>
		/// <returns></returns>
		public override string ToString()
		{
			return string.Format("{0} {1} {2}", Attribute,
				GetOperationString(OperatorType),
				Value);
		}

		#endregion
	}
}
